package networkInterface;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import main.ChatSystem;


/**
 * Implements TCP receiving of FileMessage objects
 * 
 * <p>
 * <ul>
 * <li>Project: 	ChatSystemG3</li>
 * <li>Called by: 	ChatNI</li>
 * </ul>
 * </p>
 * 
 * @author COMBES Nicolas - LECHANTRE Arnaud
 * @see ChatNIReceiver
 * @see Runnable
 */
public class ChatNIFileReceiver extends ChatNIReceiver {

	/**
	 * Socket server that will receive all tcp connexion requests
	 */
	private static ServerSocket sockServ; 
	/**
	 * Socket that will receive the FileMessage
	 */
	private Socket socket; 
	/**
	 * Path to save files
	 */
	private File directory;
	/**
	 * Concerned interface
	 */
	private FromNetwork chatNi;
	/**
	 * Unique conversation id
	 */
	private int convId;

	
	/**
	 * construct
	 * @param chatNI
	 * @param listeningPort
	 * @param directory
	 * @param convId
	 */
	public ChatNIFileReceiver(FromNetwork chatNI, int listeningPort,
			File directory, int convId) {
		super(chatNI);

		if (sockServ == null) {
			// If we are the first instance of the class, we initialize the
			// SocketServer
			try {
				ChatNIFileReceiver.sockServ = new ServerSocket(listeningPort);
				if (ChatSystem.debugMode)
					System.out
							.println("networkInterface.ChatNIFileReceiver: File recption socket waiting for connection on port "
									+ listeningPort);
				this.directory = directory;
				this.convId = convId;
				// We do not forget to save the boundary of the package in order
				// to be able to inform the controller when a message is
				// received.
				this.chatNi = chatNI;
			} catch (IOException e) {
				if (ChatSystem.debugMode)
					System.out
							.println("networkInterface.ChatNIFileReceiver: Error : another socket is already opened in this port");
				e.printStackTrace();
			}
		} else {
			if (ChatSystem.debugMode)
				System.out
						.println("networkInterface.ChatNIFileReceiver: File reception socket waiting for connection on port "
								+ listeningPort);
			this.directory = directory;
			this.convId = convId;
			// We do not forget to save the boundary of the package in order to
			// be able to inform the controller when a message is received.
			this.chatNi = chatNI;
		}

	}

	
	/**
	 * @see Runnable
	 */
	@Override
	public void run() {
		InputStream in;
		try {
			this.socket = ChatNIFileReceiver.sockServ.accept();
			if (ChatSystem.debugMode)
				System.out
						.println("networkInterface.ChatNIFileReceiver: File recption socket oppened on port "
								+ ChatSystem.tcpPort);

		} catch (IOException e1) {
			if (ChatSystem.debugMode)
				System.out
						.println("networkInterface.ChatNIFileReceiver: Couldn't perform accept.");
			e1.printStackTrace();

		}

		try {
			in = this.socket.getInputStream();
			// reader = new BufferedReader(new InputStreamReader(in));

			// At this step, the file is totaly received
			// We now have to save it at the required destination
			// So we create a new file at the destination
			File f2 = this.directory;
			f2.canWrite();

			// Then we create an input and an output stream to transfer the file
			byte buffer[] = new byte[5000];
			int nbLecture;
			FileOutputStream destination = new FileOutputStream(f2);

			// finaly we transfer the file
			BufferedOutputStream bos = new BufferedOutputStream(destination);
			/* Writing directly into the stream */
			while ((nbLecture = in.read(buffer)) != -1) {
				destination.write(buffer, 0, nbLecture);
			}
			/* Closing stream and socket */
			this.socket.close();
			// And when it's finished; we close the streams.
			destination.close();

			// And notify the controller
			this.chatNi.notifyFileReceived(this, this.convId);
			if (ChatSystem.debugMode)
				System.out
						.println("networkInterface.ChatNIFileReceiver: File totaly received");
			// Then we close the opened socket
			this.socket.close();
		} catch (IOException e) {
			this.chatNi.notifyFileReceptionAbort(this, this.convId);
			if (ChatSystem.debugMode)
				System.out.println("networkInterface.ChatNIFileReceiver: Reception failed : impossible to get the input stream");
		}

	}

	
	/**
	 * Closes socket
	 * @see ChatNIReceiver
	 */
	@Override
	public void close() {
		super.close();
		try {
			this.socket.close();
		} catch (IOException e) {
		}
	}
}
